//
//  GameViewController.swift
//  BombCar
//
//  Created by 时空矩人 on 16/4/29.
//  Copyright (c) 2016年 时空矩人. All rights reserved.
//

import UIKit
import QuartzCore
import SceneKit
import SpriteKit

struct CollisionCategory {
    
    static let None: Int = 0b00000000
    static let All: Int = 0b11111111
    
    //外围&建筑
    static let Map: Int = 0b00000001
    //主角
    static let Hero: Int = 0b00000010
    //坏蛋
    static let Monster: Int = 0b00000100
    //子弹
    static let Bullet: Int = 0b00001000
    //树
    static let Tree: Int = 0b00010000
    //平民车
    static let Car: Int = 0b00100000
    //路
    static let Road: Int = 0b01000000
}

class GameViewController: UIViewController {
    
    //MARK: - 变量 & 常量
    var scnView: SCNView!
    var scnScene: SCNScene!
    var cameraNode: SCNNode!
    
    var map: Map!
    var mapNode: SCNNode!
    var heroNode: SCNNode!
    //为什么不能这样定义: var commonCars: [SCNNode]!, 而必须用下面的定义
    var commonCars = [SCNNode]()
//    var roadBlocks = [SCNNode]()
    var roadPositions = [(i: Int, x: Float, z: Float)]()
    
    //HUD
    var hudOverLayer: SKScene!
    var joystick = Joystick()
    
    //MARK: 移动相关
    //控制器
    var forwardDirectionVector: SCNVector3!
    let heroMoveSpeed: Float = 0.2
    
    //普通车辆移动相关
    let cMoveSpeed = 0.1
    var cLeft: SCNAction!
    var cRight: SCNAction!
    var cForward: SCNAction!
    var cBack: SCNAction!
    
    
//MARK: - viewDidLoad方法
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupView()
        setupScene()
        setupNodes()
        setupHUD()
        
        setupActions()
        setupTraffic()
        
        setupSounds()
        
    }
    
//MARK: - 自定义方法
    func setupView() {
        
        scnView = self.view as! SCNView
        scnView.delegate = self
        scnView.backgroundColor = UIColor.blueColor()
        scnView.showsStatistics = true
//        scnView.allowsCameraControl = true
        scnView.autoenablesDefaultLighting = true
        
    }
    
    func setupScene() {
        scnScene = SCNScene()
        scnScene.physicsWorld.gravity = SCNVector3(x: 0, y: -9, z: 0)
        scnScene.background.contents = UIImage(named: "img_skybox.jpg")
        scnView.scene = scnScene
    }
    
    func setupNodes() {
        
        //设置整体地图
        //generate map
        map = Map(image: UIImage(named:"T_Map")!)
        
        for i in 0..<map.entities.count {
            
            let entity = map.entities[i]
            switch entity.type {
                
            case .Stone:
                let stoneNode = setStaticNode("art.scnassets/LargeTree.scn", nodeName: "LargeTree", entity: entity, categoryBitMask: CollisionCategory.Map)
                scnScene.rootNode.addChildNode(stoneNode)
                
            case .Hero:
                heroNode = setDynamicNode("art.scnassets/MrPig.scn", nodeName: "MrPig", physicsGeomegry: SCNCylinder(radius: 0.2, height: 1), categoryBitMask: CollisionCategory.Hero, collisionBitMask: CollisionCategory.All ^ CollisionCategory.Bullet, entity: entity, nodeLocation: i)
                scnScene.rootNode.addChildNode(heroNode)
                
                setRoad(entity, num: i)
                
            case .Monsters:
                let monsterNode = setDynamicNode("art.scnassets/SUV.scn", nodeName: "SUV", physicsGeomegry: SCNBox(width: 0.5, height: 0.5, length: 0.8, chamferRadius: 0),categoryBitMask: CollisionCategory.Monster, collisionBitMask: CollisionCategory.All, entity: entity, nodeLocation: i)
                scnScene.rootNode.addChildNode(monsterNode)
                
                setRoad(entity, num: i)
                
            case .SmallCars:
                
                let smallCarNode = setDynamicNode("art.scnassets/Mini.scn", nodeName: "Mini", physicsGeomegry: SCNBox(width: 0.5, height: 0.5, length: 0.5, chamferRadius: 0),categoryBitMask: CollisionCategory.Car, collisionBitMask: CollisionCategory.All, entity: entity, nodeLocation: i)
                scnScene.rootNode.addChildNode(smallCarNode)
                self.commonCars.append(smallCarNode)
                
                setRoad(entity, num: i)
                
            case .BigCars:
                
                let bigCarNode = setDynamicNode("art.scnassets/Bus.scn", nodeName: "Bus", physicsGeomegry: SCNBox(width: 0.5, height: 0.5, length: 1.0, chamferRadius: 0),categoryBitMask: CollisionCategory.Car, collisionBitMask: CollisionCategory.All, entity: entity, nodeLocation: i)
                scnScene.rootNode.addChildNode(bigCarNode)
                self.commonCars.append(bigCarNode)
                
               setRoad(entity, num: i)
                
            case .Trees:
                let treeNode = setStaticNode("art.scnassets/MediumTree.scn", nodeName: "MediumTree", entity: entity, categoryBitMask: CollisionCategory.Tree)
                scnScene.rootNode.addChildNode(treeNode)
                
            case .Buildings:
                let buildingNode = setStaticNode("art.scnassets/House.scn", nodeName: "House", entity: entity, categoryBitMask: CollisionCategory.Map)
                scnScene.rootNode.addChildNode(buildingNode)
                
            case .Road:
                setRoad(entity, num: i)
                
                
            default:
                break
            }
            
        }
        
        cameraNode = SCNNode()
        cameraNode.position = SCNVector3(x: heroNode.position.x, y: 10, z: heroNode.position.z)
        cameraNode.rotation = SCNVector4(x: 1, y: 0, z: 0, w: -89.49)
//        heroNode.addChildNode(cameraNode)
        scnScene.rootNode.addChildNode(cameraNode)
        
        //add camera
        let camera = SCNCamera()
        camera.zNear = 0.01
//        camera.zFar = Double(max(map.width, map.height))
        cameraNode.camera = camera
        
        
        //create map node
        mapNode = SCNNode()
        
        //set up map physics
        mapNode.physicsBody = SCNPhysicsBody(type: .Static, shape: SCNPhysicsShape(node: mapNode, options: [SCNPhysicsShapeKeepAsCompoundKey: true]))
        mapNode.physicsBody?.categoryBitMask = CollisionCategory.Map
        mapNode.physicsBody?.collisionBitMask = CollisionCategory.All
        mapNode.physicsBody?.contactTestBitMask = ~0
        scnScene.rootNode.addChildNode(mapNode)
        
        //add floor
        let floorNode = SCNScene(named: "art.scnassets/Floor.scn")!.rootNode.childNodeWithName("Grass", recursively: false)!
        
        floorNode.position = SCNVector3(x: Float(map.width) * 0.5, y: 0, z: Float(map.height) * 0.5)
        mapNode.addChildNode(floorNode)
        
    }
    
    //MARK: staticNode
    func setStaticNode(fileName: String, nodeName: String, entity: Entity, categoryBitMask: Int) -> SCNNode {
        let stoneNode = SCNScene(named: fileName)?.rootNode.childNodeWithName(nodeName, recursively: false)
        stoneNode!.position = SCNVector3(x: entity.x, y: 0, z: entity.y)
        stoneNode!.physicsBody = SCNPhysicsBody(type: .Static, shape: SCNPhysicsShape(geometry: stoneNode!.geometry!, options: nil))
        stoneNode!.physicsBody?.categoryBitMask = categoryBitMask
        stoneNode!.physicsBody?.collisionBitMask = CollisionCategory.All
        stoneNode!.physicsBody?.contactTestBitMask = ~0
        
        return stoneNode!
        
    }
    
    //MARK: setDynamicNode
    func setDynamicNode(fileName: String, nodeName: String, physicsGeomegry: SCNGeometry, categoryBitMask: Int,collisionBitMask: Int, entity: Entity, nodeLocation: Int) -> SCNNode {
        
        let node = SCNScene(named: fileName)?.rootNode.childNodeWithName(nodeName, recursively: false)
        
        node!.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: SCNPhysicsShape(geometry: physicsGeomegry, options: nil))
        //angularDamping: 设置角阻尼, 它用来模拟物体在气体或者液体中的角阻尼
        node!.physicsBody?.angularDamping = 0.99999
        //阻尼系数
        node!.physicsBody?.damping = 0.99999
        //滚动摩擦
        node!.physicsBody?.rollingFriction = 0
        //摩擦
        node!.physicsBody?.friction = 0
        //补偿: 用来描述物体获得或失去了多少动量
        node!.physicsBody?.restitution = 0
        //速率因素
        node!.physicsBody?.velocityFactor = SCNVector3(x: 1, y: 0, z: 1)
        //标记了物体属于那一类物体
        node!.physicsBody?.categoryBitMask = categoryBitMask
        //可以发生碰撞的物体
        node!.physicsBody?.collisionBitMask = collisionBitMask
        //MARK: 不知道为什么这么写
        node!.physicsBody?.contactTestBitMask = ~0
        node!.position = SCNVector3(x: entity.x, y: 0.2, z: entity.y)
        
        //通过判断该node上下, 左右的node的类型来给该node设置方向
//        print("\(entity.type) = \(nodeLocation)")
        let upNode = map.entities[nodeLocation - 32]
        let downNode = map.entities[nodeLocation + 32]
        
        if upNode.type != EntityType.Road || downNode.type != EntityType.Road {
            node!.rotation = SCNVector4Make(0, 1.0, 0, 1.57)
            //                print(node!.rotation)
        }
        
        return node!
        
    }
    
    //MARK: setRoad(为了简化代码而提取出来的方法)
    func setRoad(entity: Entity, num: Int) {
        
        let roadNode = SCNScene(named: "art.scnassets/Road.scn")?.rootNode.childNodeWithName("Road2", recursively: false)
        roadNode!.position = SCNVector3(x: entity.x, y: 0.08, z: entity.y)
        scnScene.rootNode.addChildNode(roadNode!)
        
        
        //通过计算i来得到当前road所在的位置
        let x = Float(num / 32) + 0.5
        let z = Float(num % 32) + 0.5
        let location = (i: num, x: x, z: z)
        roadPositions.append(location)
    }
    
    func setupHUD() {
        
        hudOverLayer = SKScene(size: UIScreen.mainScreen().bounds.size)
        hudOverLayer.scaleMode = SKSceneScaleMode.AspectFill
        scnView.overlaySKScene = hudOverLayer
        
        let jsThumb = SKSpriteNode(imageNamed: "Control_Cen")
        let jsBackdrop = SKSpriteNode(imageNamed: "Control_Bg")
        let joys = Joystick()
        joys.setThumbAndBackDrop(aNode: jsThumb, bgNode: jsBackdrop)
        self.joystick = joys
        
        //需要改进
        self.joystick.position = CGPoint(x: jsBackdrop.frame.width / 1.5, y: jsBackdrop.frame.height / 1.5)
        self.hudOverLayer.addChild(self.joystick)
        
//        let arr = SKSpriteNode(imageNamed: "Arrow")
//        let fig = SKSpriteNode(imageNamed: "Fig")
//        
//        self.hudOverLayer.addChild(<#T##node: SKNode##SKNode#>)
        
    }
    
    func setupActions() {
        
        //普通车
        let duration = 2.0
        let moveLeftAction = SCNAction.moveByX(-1, y: 0, z: 0, duration: duration)
        let moveRightAction = SCNAction.moveByX(1, y: 0, z: 0, duration: duration)
        let moveForwardAction = SCNAction.moveByX(0, y: 0, z: -1, duration: duration)
        let moveBackwardAction = SCNAction.moveByX(0, y: 0, z: 1, duration: duration)
        
        let turnLeftAction = SCNAction.rotateToX(0, y: convertToRadians(-90), z: 0, duration: duration, shortestUnitArc: true)
        let turnRightAction = SCNAction.rotateToX(0, y: convertToRadians(90), z: 0, duration: duration, shortestUnitArc: true)
        let turnForwardAction = SCNAction.rotateToX(0, y: convertToRadians(180), z: 0, duration: duration, shortestUnitArc: true)
        let turnBackwardAction = SCNAction.rotateToX(0, y: convertToRadians(0), z: 0, duration: duration, shortestUnitArc: true)
        
        //左转
        cLeft = SCNAction.group([turnLeftAction, moveLeftAction])
        //右转
        cRight = SCNAction.group([turnRightAction, moveRightAction])
        //向前
        cForward = SCNAction.group([turnForwardAction, moveForwardAction])
        //向后
        cBack = SCNAction.group([turnBackwardAction, moveBackwardAction])
        
    }
    
    func setupTraffic() {
        
        //设置普通车子的运动
        for node in self.commonCars {
            
            let x = node.position.x
            let z = node.position.z
            let nodeLoc = (x: x, z: z)
            let i = Int((nodeLoc.x-0.5)*32 + (nodeLoc.z-0.5))
            for pos in roadPositions {
                
                if i + 1 == pos.i {
//                    node.runAction(cRight)
                } else if i - 32 == pos.i {
//                    node.runAction(cForward)
                } else if i + 32 == pos.i {
//                    node.runAction(cBack)
                } else {
//                    node.runAction(cLeft)
                }
            }
        }
    }
    
    func setupSounds() {
    }
    
    //MARK: 一些辅助方法(到底有什么用, 暂时还不清楚)
    func rotateVectorByAngleInRadians(vector: SCNVector3, angle: Float) -> SCNVector3 {
        
        return SCNVector3(x: cosf(angle)*vector.x+sinf(angle)*vector.z, y: vector.y, z: -sinf(angle)*vector.x+cosf(angle)*vector.z)
        
    }
    
    //角度转弧度
    func convertToRadians(angle:CGFloat) -> CGFloat {
        let DegreesPerRadians = Float(M_PI/180)
        return CGFloat(CGFloat(angle) * CGFloat(DegreesPerRadians))
    }
    
    //弧度转角度
    func convertToDegrees(angle:Float) -> Float {
        let RadiansPerDegrees = Float(180/M_PI)
        return angle * RadiansPerDegrees
    }
    
    
//MARK: - 系统自带方法
    override func shouldAutorotate() -> Bool {
        return true
    }
    
    override func prefersStatusBarHidden() -> Bool {
        return true
    }
    
    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return .AllButUpsideDown
        } else {
            return .All
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

}

//MARK: - 代理方法
extension GameViewController: SCNSceneRendererDelegate {
    
    func renderer(renderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
        
        if self.joystick.velocity != CGPointZero {
            
            self.forwardDirectionVector = SCNVector3(x: 0, y: 0, z: 1)
            self.forwardDirectionVector = self.rotateVectorByAngleInRadians(self.forwardDirectionVector, angle: joystick.angularVelocity)
//            print(forwardDirectionVector)
            
            heroNode.position = SCNVector3(x: heroNode.position.x - forwardDirectionVector.x * heroMoveSpeed, y: heroNode.position.y + forwardDirectionVector.y, z: heroNode.position.z - forwardDirectionVector.z * heroMoveSpeed)
            heroNode.rotation = SCNVector4(x: 0, y: 1, z: 0, w: joystick.angularVelocity + 3.14)
            
            cameraNode.position = SCNVector3(x: cameraNode.position.x - forwardDirectionVector.x * heroMoveSpeed, y: cameraNode.position.y + forwardDirectionVector.y, z: cameraNode.position.z - forwardDirectionVector.z * heroMoveSpeed)
            
            
            
            
        }
        
    }
}




